﻿using System;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using AutoFixture;
using AutoFixture.AutoMoq;
using Sustainalytics.ClientDW.Entities;
using Sustainalytics.Controversies.BusinessLogic;

namespace Sustainalytics.Companies.Tests
{
    [TestClass]
    public class CompaniesSearchTest
    {
        /*[TestMethod]
        public void FindCompanies_Many_Values_Should_Call_Contains_Expression()
        {

            //Arrange
            var fixture = new Fixture().Customize(new AutoMoqCustomization());
            var mapMoq = fixture.Freeze<Mock<IPlainBl<CompanySearch>>>();
            var dataPrepare = fixture.CreateMany<CompanySearch>(100).ToList();
            mapMoq.Setup(a => a.ReadAllWhere(It.IsAny<Expression<Func<CompanySearch, bool>>>(), It.IsAny<int?>(), It.IsAny<int?>())).Returns(
                (Expression<Func<CompanySearch, bool>> d, int? a, int? e) => dataPrepare.Where(d.Compile()).ToList());
            var sut = fixture.Create<CompanySearchLogic>();
            //Act
            var param = dataPrepare.Select(a => a.IdentifierValue).Take(10).ToArray();
            var output = sut.FindCompanies(0,100,param);
            //Assert
            var expectedValues = dataPrepare.Where(a => param.Contains(a.IdentifierValue)).ToList();
            Assert.IsTrue(
                expectedValues.Select(a => a.IdentifierValue).SequenceEqual(output.Select(a => a.IdentifierValue)));
            mapMoq.Verify(a => a.ReadAllWhere(It.IsAny<Expression<Func<CompanySearch, bool>>>(), It.IsAny<int?>(), It.IsAny<int?>()));
        }

        [TestMethod]
        
        public void FindOneCompany_ParamNull_ThrowException()
        {
            try
            {
                var fixture = new Fixture().Customize(new AutoMoqCustomization());
                var sut = fixture.Create<CompanySearchLogic>();
                sut.FindCompanies(null, null, null);
            }
            catch (Exception ex)
            {
                Assert.IsInstanceOfType(ex,typeof(ArgumentNullException));
            }
        }

        [TestMethod]
        public void FindOneCompany_SingleValue_Should_Return_OneCompany()
        {
            //Arrange
            var fixture = new Fixture().Customize(new AutoMoqCustomization());
            var mapMoq = fixture.Freeze<Mock<IPlainBl<CompanySearch>>>();
            var dataPrepare = fixture.CreateMany<CompanySearch>(10).ToList();
            mapMoq.Setup(a => a.ReadAllWhere(It.IsAny<Expression<Func<CompanySearch, bool>>>(), It.IsAny<int?>(), It.IsAny<int?>())).Returns(
                (Expression<Func<CompanySearch, bool>> d, int? a, int? e) => dataPrepare.Where(d.Compile()).ToList());
            //Act
            var sut = fixture.Create<CompanySearchLogic>();
            var output = sut.FindOneCompany(dataPrepare[0].IdentifierValue);
            var expectedValues = dataPrepare.Find(a => a.IdentifierValue == dataPrepare[0].IdentifierValue);
            //Assert
            Assert.AreEqual(expectedValues.Id, output.Id);
            mapMoq.Verify(a => a.ReadAllWhere(It.IsAny<Expression<Func<CompanySearch, bool>>>(), It.IsAny<int?>(), It.IsAny<int?>()));
        }

        [TestMethod]
        [ExpectedException(typeof (CompanySearchNotFoundException))]
        public void FindOneCompany_NoResult_Found_CompanySearchNotFound_ThrowException()
        {

            //Arrange
            var fixture = new Fixture().Customize(new AutoMoqCustomization());
            var mapMoq = fixture.Freeze<Mock<IPlainBl<CompanySearch>>>();
            var dataPrepare = fixture.CreateMany<CompanySearch>(1).ToList();
            mapMoq.Setup(a => a.ReadAllWhere(It.IsAny<Expression<Func<CompanySearch, bool>>>(), null, null)).Returns(
                (Expression<Func<CompanySearch, bool>> d, int? a, int? e) => dataPrepare.Where(d.Compile()).ToList());
            //Act
            var sut = fixture.Create<CompanySearchLogic>();
            sut.FindOneCompany(fixture.Create<string>());
        }

        [TestMethod]
        public void FindCompaniesByIdentifier_Should_Return_Many_Companies()
        {
            //Arrange
            var fixture = new Fixture().Customize(new AutoMoqCustomization());
            var mapMoq = fixture.Freeze<Mock<IPlainBl<CompanySearch>>>();
            var dataPrepare = fixture.CreateMany<CompanySearch>(50).ToList();
            foreach (var companySearch in dataPrepare)
            {
                companySearch.IdentifierTypeId = ((int) fixture.Create<IdentifierType>()).ToString();
            }
            mapMoq.Setup(a => a.ReadAllWhere(It.IsAny<Expression<Func<CompanySearch, bool>>>(), null, null)).Returns(
                (Expression<Func<CompanySearch, bool>> d, int? a, int? e) => dataPrepare.Where(d.Compile()).ToList());
            IdentifierType identifierSearch;
            IdentifierType.TryParse(dataPrepare[3].IdentifierTypeId, out identifierSearch);
            var identifierValue = dataPrepare[3].IdentifierValue;
            //Act
            var dataExpected =
                dataPrepare.Where(
                    a => a.IdentifierTypeId == ((int) identifierSearch).ToString() && a.IdentifierValue == identifierValue);
            var sut = fixture.Create<CompanySearchLogic>();
            var output = sut.FindCompaniesByIdentifier(null,null,identifierSearch, identifierValue);
            //Assert
            Assert.IsTrue(dataExpected.Select(a => a.Id).SequenceEqual(output.Select(a => a.Id)));
            mapMoq.Verify(a => a.ReadAllWhere(It.IsAny<Expression<Func<CompanySearch, bool>>>(), null, null));
        }

        [TestMethod]
        public void GetCorporateData_Return_Corporate_Data_Matching()
        {
            //Arrange
            var fixture = new Fixture().Customize(new AutoMoqCustomization());
            var mapMoqCompanySearch = fixture.Freeze<Mock<IPlainBl<CompanySearch>>>();
            var mapMoqCorporateData = fixture.Freeze<Mock<IPlainBl<CorporateData>>>();
            var dataPrepareCompanySearch = fixture.CreateMany<CompanySearch>(10).ToList();
            var dataCorporateData = fixture.CreateMany<CorporateData>(15).ToList();
            for (int i = 0; i < dataPrepareCompanySearch.Count; i++)
            {
                dataCorporateData[i].Id = dataPrepareCompanySearch[i].CompanyId;
            }
            mapMoqCompanySearch.Setup(a => a.ReadAllWhere(It.IsAny<Expression<Func<CompanySearch, bool>>>(), null, null))
                .Returns(
                    (Expression<Func<CompanySearch, bool>> d, int? a, int? e) =>
                        dataPrepareCompanySearch.Where(d.Compile()).ToList());
            mapMoqCorporateData.Setup(a => a.ReadAllWhere(It.IsAny<Expression<Func<CorporateData, bool>>>(), null, null))
                .Returns(
                    (Expression<Func<CorporateData, bool>> d, int? a, int? e) =>
                        dataCorporateData.Where(d.Compile()).ToList());
            //Act
            var sut = fixture.Create<CompanySearchLogic>();
            var output = sut.GetCorporateData(dataPrepareCompanySearch.Select(a => a.IdentifierValue).Take(4).ToArray());
            var expected =
                dataCorporateData.Where(d => dataPrepareCompanySearch.Select(a => a.CompanyId).Take(4).Contains(d.Id))
                    .ToList();
            //Assert
            Assert.IsTrue(expected.Select(a => a.Id).SequenceEqual(output.Select(c => c.Id)));
            mapMoqCompanySearch.Verify(
                a => a.ReadAllWhere(It.IsAny<Expression<Func<CompanySearch, bool>>>(), null, null));
            mapMoqCorporateData.Verify(
                a => a.ReadAllWhere(It.IsAny<Expression<Func<CorporateData, bool>>>(), null, null));

        }

        [TestMethod]
        public void FindCompanies_ThrowCompanySearchNotFoundException()
        {
            try
            {
                var fixture = new Fixture().Customize(new AutoMoqCustomization());
                var mapMoq = fixture.Freeze<Mock<IPlainBl<CompanySearch>>>();
                var sut = fixture.Create<CompanySearchLogic>();
                mapMoq.Setup(
                    a =>
                        a.ReadAllWhere(It.IsAny<Expression<Func<CompanySearch, bool>>>(), It.IsAny<int?>(),
                            It.IsAny<int?>()))
                    .Returns(new CompanySearch[0]);
                sut.FindCompanies(fixture.Create<string>());
            }
            catch (Exception ex)
            {
                Assert.IsInstanceOfType(ex,typeof(CompanySearchNotFoundException));
            }
        }

        [TestMethod]
        public void FindCompanies_CompanySearch_ReturnSomething()
        {
            var fixture = new Fixture().Customize(new AutoMoqCustomization());
            var mapMoq = fixture.Freeze<Mock<IPlainBl<CompanySearch>>>();
            mapMoq.Setup(
                a =>
                    a.ReadAllWhere(It.IsAny<Expression<Func<CompanySearch, bool>>>(), It.IsAny<int?>(),
                        It.IsAny<int?>()))
                .Returns(new CompanySearch[1]{fixture.Create<CompanySearch>()});
            var sut = fixture.Create<CompanySearchLogic>();
            var output = sut.FindCompanies(fixture.Create<string>());
            Assert.IsTrue(output.Any());
        }

        [TestMethod]
        public void FindOneCompanyByIdentifier_ThrowsCompanySearchNotFound()
        {
            try
            {
                var fixture = new Fixture().Customize(new AutoMoqCustomization());
                var mapMoq = fixture.Freeze<Mock<IPlainBl<CompanySearch>>>();
                var sut = fixture.Create<CompanySearchLogic>();
                mapMoq.Setup(
                    a =>
                        a.ReadAllWhere(It.IsAny<Expression<Func<CompanySearch, bool>>>(), It.IsAny<int?>(),
                            It.IsAny<int?>()))
                    .Returns(new CompanySearch[0]);
                sut.FindOneCompanyByIdentifier(fixture.Create<IdentifierType>(),fixture.Create<string>());
            }
            catch (Exception ex)
            {
                Assert.IsInstanceOfType(ex,typeof(CompanySearchNotFoundException));
            }
        }

        [TestMethod]
        public void FindOneCompanyByIdentifier__CompanySearch_ReturnSomething()
        {
            var fixture = new Fixture().Customize(new AutoMoqCustomization());
            var mapMoq = fixture.Freeze<Mock<IPlainBl<CompanySearch>>>();
            mapMoq.Setup(
                a =>
                    a.ReadAllWhere(It.IsAny<Expression<Func<CompanySearch, bool>>>(), It.IsAny<int?>(),
                        It.IsAny<int?>()))
                .Returns(new CompanySearch[1] { fixture.Create<CompanySearch>() });
            var sut = fixture.Create<CompanySearchLogic>();
            var output = sut.FindOneCompanyByIdentifier(fixture.Create<IdentifierType>(), fixture.Create<string>());
            Assert.IsTrue(output!=null);
        }*/
    }
}

